home *** CD-ROM | disk | FTP | other *** search
-
- /************************************************************
- * Program: CMENU Menu Compiler
- * Module: cmenu2.c
- * Menu Compiler:
- * Menu/Item Token Processing Functions
- * Written by: Leor Zolman, 7/91
- ************************************************************/
-
- #include "cmenu.h"
- #include "ccmenu.h"
-
- #include <ctype.h>
-
-
- /************************************************************
- * do_menu():
- * Process the MENU keyword
- ************************************************************/
-
- int do_menu()
- {
- int tok;
-
- if (in_menu) /* Are we currently processing a menu? */
- { /* yes. */
- warning("Endmenu missing from previous menu");
- do_endmenu(); /* give them the benefit of the doubt */
- }
-
- if ((tok = gettok()) != T_STRING)
- {
- if (n_menus)
- error("Menu name missing; menu unreachable");
- sprintf(tparam, "menu%d", n_menus + 1); /* force a name */
- ungettok(tok);
- }
-
- if (strlen(tparam) > MAX_NAME)
- {
- error("The name '%s' is too long (%d chars max)",
- tparam, MAX_NAME);
- tparam[MAX_NAME] = '\0'; /* truncate name */
- }
-
- if ((MIp = find_menu(tparam)) == NULL) /* menu exist? */
- {
- MInfo[n_menus] = create_menu(tparam); /* no. */
- if (fatal)
- return ERROR; /* creation error */
- else
- MIp = &MInfo[n_menus++]; /* OK, bump count */
- }
- else
- if (MIp -> Processed) /* redefinition? */
- return fatalerr("Duplicate Menu definition"); /* yes. */
-
- Mp = &MIp -> Menu;
- *Mp->title = *Mp->path = '\0';
- Mp->nitems = Mp->widest = 0;
- Mp->spacing = Mp->columns = Mp->escape = DEFAULT;
- Mp->align = DEFAULT;
-
- in_item = FALSE; /* state variables describing the */
- in_menu = TRUE; /* current menu being processed */
- n_items = 0;
- n_refs = 0; /* no forward item references yet */
-
- if ((tok = gettok()) != T_COLON) /* optional colon */
- ungettok(tok);
-
- return OK;
- }
-
-
- /************************************************************
- * do_title():
- * Process the TITLE clause for a menu.
- ************************************************************/
-
- int do_title()
- {
- int tok;
-
- if ((tok = gettok()) != T_STRING)
- {
- error("Title text missing");
- ungettok(tok);
- }
-
- if (!in_item) /* Before all items? */
- { /* yes. */
- if (*Mp->title)
- return error("A Menu Title has already been specified");
- strcpy(Mp->title, tparam);
- }
- else
- return error("The Menu Title must precede all Menu Items.");
-
- return OK;
- }
-
-
- /************************************************************
- * do_path():
- * Process the PATH option.
- * Note that the PATH option may apply to an entire
- * menu or just to a single menu item (determined
- * by context.)
- ************************************************************/
-
- int do_path()
- {
- int tok;
- char *cp;
-
- if ((tok = gettok()) != T_STRING)
- {
- error("Path text missing");
- ungettok(tok);
- }
-
- if (tparam[strlen(tparam)-1]=='/' || tparam[strlen(tparam)-1]=='\\')
- tparam[strlen(tparam) - 1] = '\0'; /* delete traling slash */
-
- if (!in_item) /* Referring to the menu? */
- { /* yes. */
- if (*Mp->path)
- return error("A Menu Path has already been specified");
- strcpy(Mp->path, tparam);
- }
- else
- { /* Must be for the item. */
- if (*Ip->path)
- return error("An Item Path has already been specified");
- strcpy(Ip->path, tparam);
- }
- return OK;
- }
-
-
- /************************************************************
- * do_align():
- * Process text alignment option.
- * Note: this option is a no-op. I decided there wasn't
- * any real need for any other than left-justified item
- * alignment. But, in case anyone thinks of a use for it,
- * I'm leaving in the ability to process the option.
- ************************************************************/
-
- int do_align()
- {
- int tok;
-
- if (in_item)
- return error("The Align clause must precede all Menu Items.");
-
- if (Mp->align)
- return error("Align option already specified for this menu");
-
- switch (tok = gettok())
- {
- case T_LEFT:
- Mp->align = 'L';
- break;
-
- case T_RIGHT:
- Mp->align = 'R';
- break;
-
- case T_CENTER:
- Mp->align = 'C';
- break;
-
- default:
- ungettok(tok);
- return error("Align missing valid modifier");
- }
- return OK;
- }
-
-
- /************************************************************
- * do_spacing():
- * Process the SPACING option (applies
- * to menus only.)
- ************************************************************/
-
- int do_spacing()
- {
- int tok;
-
- if ((tok = gettok()) != T_VALUE)
- {
- error("Spacing value missing");
- ungettok(tok);
- }
-
- if (in_item)
- return error("Spacing option must precede all menu items");
-
- if (Mp->spacing)
- return error("Spacing option already specified");
-
- /* only single and double spacing supported */
- if (vparam != 1 && vparam != 2)
- return error("Spacing value must be either 1 or 2");
-
- Mp->spacing = vparam;
- return OK;
- }
-
-
- /************************************************************
- * do_columns():
- * Process the COLUMNS option
- ************************************************************/
-
- int do_columns()
- {
- int tok;
-
- if ((tok = gettok()) != T_VALUE)
- {
- error("Columns value missing");
- ungettok(tok);
- }
-
- if (in_item)
- return error("Columns option must precede all menu items");
-
- if (Mp->columns)
- return error("Columns option already specified");
-
- if (vparam < 1 || vparam > 6) /* 6 seems a reasonable max. */
- return error("Columns value must be between 1 and 6");
- Mp->columns = vparam;
- return OK;
- }
-
-
- /************************************************************
- * do_escape():
- * Process "escape" and "noescape" menu options
- ************************************************************/
-
- int do_escape()
- {
- if (in_item)
- return error("\"%s\" must appear before all menu items",
- keywords[token].keyword);
-
- if (Mp->escape)
- return error("Escape option already specified");
- Mp->escape = (token == T_ESCAPE) ? YES : NO;
-
- return OK;
- }
-
-
- /************************************************************
- * do_endmenu():
- * Process ENDMENU keyword
- ************************************************************/
-
- int do_endmenu()
- {
- int i;
-
- if (!n_items)
- error("No menu items specified for this menu");
-
- for (i = 0; i < n_refs; i++) /* check for unresolved */
- { /* forward Item references */
- if (*fwd_refs[i].refp == UNDEF_FWD)
- {
- int save_lineno = lineno;
- lineno = fwd_refs[i].lineno;
- error("Unresolved reference to Item \"%s\"",
- fwd_refs[i].iname);
- lineno = save_lineno;
- }
- }
-
- in_menu = in_item = FALSE; /* done with current menu */
- MIp -> Processed = TRUE; /* it is now processed */
- Mp -> nitems = n_items;
- return OK;
- }
-
-
- /************************************************************
- * do_item():
- * Process the ITEM clause. Create a new ite
- * and fill in any existing forward references to it.
- ************************************************************/
-
- int do_item()
- {
- int tok, i;
- char *cp, c;
-
- if (n_items)
- itemcheck(); /* check for previous item's completion */
-
- if ((tok = gettok()) != T_STRING) /* label specified? */
- { /* If not, stuff unique */
- sprintf(tparam,"dummy!%d", n_items); /* dummy name in */
- ungettok(tok);
- }
- else
- {
- if (strlen(tparam) > MAX_NAME)
- {
- error("Item name \"%s\" too long. Max %d chars.",
- tparam, MAX_NAME);
- tparam[MAX_NAME] = '\0';
- }
- else for (cp = tparam; c = *cp; cp++)
- if (!(isalpha(c) || isdigit(c) || c == '_'))
- {
- error("Invalid char in identifier name: \"%s\"",
- tparam);
- *cp = '\0';
- break;
- }
- }
-
- if ((IIp = find_item(tparam)) != NULL) /* Item name found? */
- return error("Item name previously used.");
-
- if ((MIp->Items[n_items] = IIp = create_item(tparam))
- == NULL)
- return ERROR;
-
- in_item = TRUE;
- Ip = &IIp->Item;
-
- for (i = 0; i < n_refs; i++) /* check for fwd refs */
- if (!strcmp(fwd_refs[i].iname, tparam))
- *fwd_refs[i].refp = n_items; /* fill in with item # */
-
- n_items++; /* bump item count */
-
- if ((token = gettok()) != T_COLON) /* optional colon? */
- {
- ungettok(token); /* if not, all done */
- return OK;
- }
-
- if ((token = gettok()) == T_STRING) /* short-form text? */
- return do_text2(); /* if so, go process */
- else
- {
- ungettok(token); /* else all done */
- return OK;
- }
- }
-
-
- /************************************************************
- * do_opts():
- * Process simple "binary" options for prompt,
- * pre- and post-clear specifications.
- * Note: upon entry, global "token" contains the
- * value of the token to be processed.
- ************************************************************/
-
- int do_opts()
- {
- if (!in_item)
- return error("\"%s\" only valid within an item",
- keywords[token].keyword);
-
- switch(token)
- {
- case T_PROMPT: case T_PAUSE:
- case T_NOPROMPT: case T_NOPAUSE:
- if (Ip->prompt != DEFAULT)
- return error("Prompt option already specified");
- Ip->prompt= (token==T_PROMPT || token==T_PAUSE)? YES :NO;
- break;
-
- case T_POSTCLEAR: /* these are actually no-ops, */
- case T_NOPOSTCLEAR: /* but again, I've left them in */
- if (Ip->post_clear != DEFAULT)
- return error("Postclear option already specified");
- Ip->post_clear = (token == T_POSTCLEAR) ? YES : NO;
- break;
-
- case T_PRECLEAR:
- case T_NOPRECLEAR:
- if (Ip->pre_clear != DEFAULT)
- return error("Preclear option already specified");
- Ip->pre_clear = (token == T_PRECLEAR) ? YES : NO;
- break;
- }
- return OK;
- }
-
-
- /************************************************************
- * do_nextitem():
- * Process NEXTIEM option.
- ************************************************************/
-
- int do_nextitem()
- {
- int tok;
-
- if (Ip->nextcode != DEFAULT)
- error("Nextitem option already specified");
-
- switch (tok = gettok())
- {
- case T_FIRST:
- Ip->nextcode = NXT_FIRST;
- break;
-
- case T_LAST:
- Ip->nextcode = NXT_LAST;
- break;
-
- case T_NEXT:
- Ip->nextcode = NXT_NEXT;
- break;
-
- case T_STRING:
- Ip->nextcode = NXT_DIRECT;
- if (find_item(tparam))
- Ip->nextitem = item_num;
- else
- { /* record forward item reference */
- strcpy(fwd_refs[n_refs].iname, tparam);
- fwd_refs[n_refs].refp = &Ip->nextitem;
- fwd_refs[n_refs++].lineno = lineno;
- Ip->nextitem = UNDEF_FWD;
- }
- break;
-
- default:
- ungettok(tok);
- return error("Bad Nextitem specification");
- }
- return OK;
- }
-
-
- /************************************************************
- * do_text():
- * Process Text parameter
- ************************************************************/
-
- int do_text()
- {
- int tok;
-
- if (!in_item)
- return error("Text clause must be within an item");
- if (*Ip->text)
- return error("Text clause already specified for this item");
-
- if ((tok = gettok()) != T_STRING)
- {
- ungettok(tok);
- return error("Text clause specified without the text.");
- }
-
- return do_text2();
- }
-
-
- /************************************************************
- * do_text():
- * Continued TEXT clause processing, shared between
- * do_text() and do_item().
- ************************************************************/
-
- int do_text2()
- {
- if (strlen(tparam) > MAX_TXTWID)
- {
- *Ip->text = 'x'; /* to avoid "missing text" error */
- return error("Text is too long; maximum %d chars",
- MAX_TXTWID);
- }
- else
- strcpy(Ip->text, tparam);
-
- if (strlen(tparam) > Mp -> widest)
- Mp -> widest = strlen(tparam);
-
- return OK;
- }
-
-
- /************************************************************
- * do_action():
- * Process standard action, Exit, Lmenu or Emenu clause
- ************************************************************/
-
- int do_action()
- {
- int tok;
- int old_acttyp = Ip->acttyp;
-
- if (!in_item)
- return error("%s clause only valid within an item",
- keywords[token].keyword);
-
- if (token == T_EXIT || (tok = gettok()) == T_EXIT)
- Ip->acttyp = ACT_EXIT;
- else
- if (tok != T_STRING)
- {
- ungettok(tok);
- error("Incomplete %s specification",
- keywords[token].keyword);
- }
- else
- if (strlen(tparam) > MAX_CMD)
- error("%s parameter too long (max %d chars)",
- keywords[token].keyword, MAX_CMD);
- else
- switch(token)
- {
- case T_ACTION:
- strcpy(Ip->action, tparam);
- Ip->acttyp = ACT_CMND;
- break;
-
- case T_LMENU:
- if (find_menu(tparam) != NULL) /* named menu defined? */
- Ip->lmenunum = menu_num; /* yes. */
- else
- { /* no. create entry */
- MInfo[n_menus] = create_menu(tparam);
- if (fatal)
- return ERROR; /* creation error */
- else
- Ip->lmenunum = n_menus++; /* OK; assign. */
- }
-
- Ip->acttyp = ACT_LMENU;
- break;
-
- case T_EMENU:
- strcpy(Ip->action, tparam);
- Ip->acttyp = ACT_EMENU;
- break;
- }
-
- if (old_acttyp)
- return error("Only one Action clause allowed per item");
-
- return OK;
- }
-
-
- /************************************************************
- * do_help():
- * Process help clause.
- ************************************************************/
-
- int do_help()
- {
- int tok;
-
- if (!in_item)
- return error("Help clause only valid within an item");
-
- if ((tok = gettok()) != T_STRING)
- {
- ungettok(tok);
- return error("No Help text specified");
- }
-
- if (strlen(tparam) > MAX_HELP)
- return error("Help text too long (max %d chars)",
- MAX_HELP);
-
- if (*Ip->help)
- return error("Only one help line allowed per item");
-
- strcpy(Ip->help, tparam);
- return OK;
- }
-
-
- /************************************************************
- * do_err():
- * Diagnose hopelessly bad syntax (i.e., encountering a
- * totally unexpected keyword)
- ************************************************************/
-
- int do_err()
- {
- return fatalerr("Unrecoverable Syntax error.");
- }
-
-